#!/usr/bin/env python
#
# Arkaya Arcade Frontend
#
# http://www.strickerz.dk
#
# Released under the GNU General Public License

try:
	import sys
	import pygame
	import os
	import arkaya_resources
	import arkaya_util
	import math
	import ConfigParser
	import time
	from romsax import *
	from pygame.locals import *
	from xml.dom import minidom
	from constants import *
	from arkaya_sprites import *
except ImportError, err:
	print "couldn't load module. %s" % (err)
	sys.exit(2)

class GameEngineList():

	def __init__(self, screen):
		self.gameengines = []

		self.loadEmulators()
		
		self.index = 0
		self.nextindex = self.index + 1
		self.previousindex = self.index -1
		self.screen = screen
		self.prevIndex = "_NOTHING"

	def loadEmulators(self):
		ini_file = os.path.join(APP_PATH, 'arkaya.ini')

		parser = ConfigParser.ConfigParser()		
		parser.read(ini_file)
		
		emulators = parser.items("emulators")
		
		for emulator in emulators:
			if emulator[1] == "true":
				#TODO: error handling to be done
				emulator_ini = os.path.join(APP_PATH, "config", emulator[0] + ".ini")
				parser.read(emulator_ini)
				
				name = parser.get("emulator", "emulator_name")
				self.gameengines.append(GameEngine(name, emulator[0]))
		

	def getSelected(self):
		gameengine = self.gameengines[self.index]
		return gameengine

	def getPrevSelected(self):
		if self.prevIndex != "_NOTHING":
			gameengine = self.gameengines[self.prevIndex]
			return gameengine
		return False
	
	def getPrevious(self):
		selected = self.getSelected()
		if selected.isFrozen():
			self.prevIndex = self.index
			self.getSelected().thaw("R")
			self.index = self.index - 1
			if self.index < 0:
				self.index = len(self.gameengines) - 1
			self.getSelected().zero("R")

	def getNext(self):
		selected = self.getSelected()
		if selected.isFrozen():
			self.prevIndex = self.index
			self.getSelected().thaw("L")
			self.index = self.index + 1
			if self.index >= len(self.gameengines):
				self.index = 0
			self.getSelected().zero("L")

	def update(self):
		selected = self.getSelected()
		selected.update()
		prev = self.getPrevSelected()
		if prev:
			prev.update()

	def draw(self):
		gameenginesprite = pygame.sprite.RenderPlain(self.getSelected())
		gameenginesprite.draw(self.screen)
		prev = self.getPrevSelected()
		if prev:
			gameenginesprite = pygame.sprite.RenderPlain(prev)
			gameenginesprite.draw(self.screen)


class RomInfo():
	def __init__(self, screen, rom):
		self.screen = screen
		self.rom = rom
		self.rom_info_left = INFO_BOX_LEFT
		self.rom_info_top = INFO_BOX_TOP
		self.rom_info_width = INFO_BOX_WIDTH
		self.rom_info_height = INFO_BOX_HEIGHT
		
		self.rominfo_rect = Rect(self.rom_info_left, self.rom_info_top, self.rom_info_width, self.rom_info_height)
		
		self.font = pygame.font.Font('data/slkscr.ttf', 14)
		self.colour = 255
		self.jump = -5
	
	def draw(self):
#		pygame.draw.rect(self.screen, (self.col, 0, 0), (INFO_BOX_LEFT, INFO_BOX_TOP, INFO_BOX_WIDTH, INFO_BOX_HEIGHT), 1)
		self.colour = self.colour + self.jump
		if self.colour <= 0:
			self.jump = 5
		elif self.colour >= 255:
			self.jump = -5

		title = self.font.render(str(self.fitText(self.rom.title, self.rom_info_width)), 0, (self.colour, 0, 0))
		title_rect = title.get_rect()
		
		title_rect.centerx = self.rominfo_rect.centerx
		title_rect.top = self.rom_info_top + 10
		self.screen.blit(title, title_rect)

		if self.rom.description:
			description = self.font.render(str(self.fitText(self.rom.description, self.rom_info_width)), 0, (self.colour, 0, 0))
			description_rect = description.get_rect()
			
			description_rect.centerx = self.rominfo_rect.centerx
			description_rect.top = self.rom_info_top + 20
			self.screen.blit(description, description_rect)

		author = self.font.render(str(self.fitText(self.rom.author.encode('utf-8'), self.rom_info_width)), 0, (self.colour, 0, 0))
		author_rect = author.get_rect()
		
		author_rect.centerx = self.rominfo_rect.centerx
		author_rect.top = self.rom_info_top + 30
		self.screen.blit(author, author_rect)

		year = self.font.render(str(self.rom.year), 0, (self.colour, 0, 0))
		year_rect = year.get_rect()
		
		year_rect.centerx = self.rominfo_rect.centerx
		year_rect.top = self.rom_info_top + 40
		self.screen.blit(year, year_rect)
		
	def update(self, rom):
		self.rom = rom
		self.draw()

	def fitText(self, text, max_length):
		text_len = 0
		chars = 0
		final_text = text
		if self.font.size(text) > max_length - 10 and text:
			metrics = self.font.metrics(text)
			for m in metrics:
				text_len += m[4]
				if text_len < max_length - 10:
					chars += 1
				else:
					chars = chars - 2
					final_text = text[0:chars] + "..."
					break
		
		return final_text


class RomList():
	""" A list of all posible games """
	def __init__(self, screen, gameengine):
		self.roms = []
		self.selected = 0
		self.position_in_slidingwindow = 0
		self.listlength = 20 # rom list entries that are visible
		self.range_start = 0
		self.range_end = self.listlength
		self.screen = screen
		self.gameengine = gameengine
		self.font = pygame.font.Font('data/slkscr.ttf', 18)
		
		if len(self.roms) < 1:
			self.loadRoms(self.gameengine, True)
		
	def loadRoms(self, gameengine, new = False):
		if self.gameengine.__dict__ != gameengine.__dict__ or new:
			self.selected = 0
			self.gameengine = gameengine
			self.roms = []
			
			# Create an instance of the Handler.
			handler = RomSaxDocumentHandler(self.roms)
			# Create an instance of the parser.
			parser = make_parser()
			# Set the content handler.
			parser.setContentHandler(handler)
			inFile = open('resources/' + self.gameengine.rom_file, 'r')
			# Start the parse.
			parser.parse(inFile)

			inFile.close()

			self.range_start = 0
			self.range_end = len(self.roms)
			self.position_in_slidingwindow = 0

			if self.range_end > self.listlength:
				self.range_end = self.listlength

	def up(self):
		if self.selected > 0:
			self.selected -= 1
			self.position_in_slidingwindow -= 1
			if self.position_in_slidingwindow == 0 and self.selected > 0:
				self.range_start -= 1
				self.range_end -= 1
				self.position_in_slidingwindow += 1

	def down(self):
		if self.selected < len(self.roms) - 1:
			self.selected += 1
			self.position_in_slidingwindow += 1
			if self.position_in_slidingwindow == self.listlength - 1 and self.selected < len(self.roms) - 1:
				self.range_start += 1
				self.range_end += 1
				self.position_in_slidingwindow -= 1
			
	def draw(self):
#		pygame.draw.rect(self.screen, (255, 0, 0), (ROM_LIST_LEFT, ROM_LIST_TOP, ROM_LIST_WIDTH, ROM_LIST_HEIGHT), 1)
#		pygame.draw.rect(self.screen, (255, 0, 0), (TITLE_SNAP_LEFT, TITLE_SNAP_TOP, TITLE_SNAP_WIDTH, TITLE_SNAP_HEIGHT), 1)
		
		offset = 0
		
		for i in range(self.range_start, self.range_end):
			title_len = 0
			chars = 0
			if self.font.size(self.roms[i].title)[0] > ROM_LIST_WIDTH - 10:
				metrics = self.font.metrics(self.roms[i].title)
				for m in metrics:
					title_len += m[4]
					if title_len < ROM_LIST_WIDTH - 10:
						chars += 1
					else:
						chars = chars - 2
						game_title = self.roms[i].title[0:chars] + "..."
						break
			else:
				game_title = self.roms[i].title
				 
			if i == self.selected:
				text = self.font.render(str(game_title), 0, (255, 0, 0))
			else:
				text = self.font.render(str(game_title), 0, (0, 255, 0))
			
			self.screen.blit(text, (ROM_LIST_LEFT + 10, ROM_LIST_TOP + 10 + offset))
			offset += self.font.get_linesize()

	def update(self, gameengine):
		self.loadRoms(gameengine, False)
		self.draw()

	def getRom(self):
		return self.roms[self.selected]

	def getGame(self):
		return self.roms[self.selected].rom_name

class Rom():
	""" A class representing a single rom """
	def __init__(self):
		self.title = ""
		self.description = ""
		self.path = ""
		self.rom_name = ""
		self.year = 1970
		self.author = ""
	
	def setTitle(self, title):
		self.title = title
		
	def setRomName(self, rom_name):
		self.rom_name = rom_name

	def getTitleSnap(self):
		if self.path:
			return self.path + "/" + self.rom_name.lower().replace('.exe', '.png')
		else:
			return self.rom_name.replace('.zip', '.png')


class Logo(pygame.sprite.Sprite):
	""" Logo """
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image, self.rect = arkaya_resources.load_png('logo.png')
		self.rect.topleft = 0, 0	

class ViewController():
	"""View Controller"""
	def __init__(self, screen, gameenginelist):
		self.screen = screen
		self.gameenginelist = gameenginelist
		self.mainview = MainView(screen, self.gameenginelist)
		self.emulatorview = EmulatorView(screen, self.gameenginelist)
		self.whodidthisview = WhoDidThisView(screen)
		self.view = self.mainview

	def setView(self, view):
		print view
		if view == "EmulatorView":
			self.view = self.emulatorview
			self.emulatorview.switch = True
		elif view == "MainView":
			self.view = self.mainview
		else:
			self.view = self.whodidthisview

	def getView(self):
		return self.view

	def getGameEngine(self):
		return self.gameenginelist.getSelected()

	def refresh(self):
		self.view.refresh()

	def left(self):
		self.view.left()

	def right(self):
		self.view.right()

	def up(self):
		self.view.up()

	def down(self):
		self.view.down()

	def reset(self):
		if isinstance(self.view, WhoDidThisView):
			self.view.reset()
		

class MainView():
	def __init__(self, screen, gameenginelist):
		self.screen = screen
		
		self.sound = Sound()
		
		# Fill background
		self.background = pygame.Surface(screen.get_size())
		self.background = self.background.convert()
		self.background.fill((0, 0, 0))

		self.gameenginelist = gameenginelist

		self.leftarrow = MovingArrow('LEFT')
		self.rightarrow = MovingArrow('RIGHT')
	
		self.arrowsprites = pygame.sprite.RenderPlain((self.leftarrow, self.rightarrow))

		# Blit everything to the screen
		self.screen.blit(self.background, (0, 0))

	def refresh(self):
		self.screen.blit(self.background, (0, 0))
		self.gameenginelist.update()
		self.gameenginelist.draw()
		self.arrowsprites.update()
		self.arrowsprites.draw(self.screen)

	def left(self):
		self.sound.play()
		self.gameenginelist.getPrevious()

	def right(self):
		self.sound.play()
		self.gameenginelist.getNext()

	def up(self):
		print "Nothing to see here"

	def down(self):
		print "Nothing to see here"

class EmulatorView():
	def __init__(self, screen, gameenginelist):
		self.screen = screen
		self.gameenginelist = gameenginelist
		self.switch = False
		self.background = pygame.Surface(screen.get_size())
		self.background = self.background.convert()
		self.background.fill((0, 0, 0))
		self.background, foo = arkaya_resources.load_png('background.png')

		self.romlist = RomList(self.screen, self.gameenginelist.getSelected())
		
		self.titlesnap = TitleSnap(self.romlist.roms[self.romlist.selected].getTitleSnap(), self.gameenginelist.getSelected())
		
		self.rominfo = RomInfo(self.screen, self.romlist.roms[self.romlist.selected])
		
		self.romstuff = pygame.sprite.RenderPlain((self.titlesnap))

		self.logo = pygame.sprite.RenderPlain((Logo()))


	def refresh(self):
		if self.romlist is None:
			self.romlist = RomList(self.screen, self.gameenginelist.getSelected())
		
		self.screen.blit(self.background, (0, 0))
		self.romlist.update(self.gameenginelist.getSelected())
		
		self.rominfo.update(self.romlist.roms[self.romlist.selected])
		
		if self.switch:
			self.titlesnap.setImage(self.romlist.roms[self.romlist.selected].getTitleSnap(), self.gameenginelist.getSelected())
			self.switch = False
		self.romstuff.update()
		self.romstuff.draw(self.screen)

		self.logo.draw(self.screen)


	def left(self):
		print "Nothing to see here"

	def right(self):
		print "Nothing to see here"
	
	def up(self):
		self.romlist.up()
		self.switch = True
		
	def down(self):
		self.romlist.down()
		self.switch = True

	def runGame(self):
		if self.gameenginelist.getSelected().name == "E-UAE":
			emulator_params = self.gameenginelist.getSelected().emulator_params + self.gameenginelist.getSelected().rom_path

			emulator_params = emulator_params + "/" + self.romlist.getGame()
		elif self.romlist.getRom().path:
			emulator_params = self.gameenginelist.getSelected().rom_path + "/" + self.romlist.getRom().path + "/" + self.romlist.getGame()
			emulator_params = emulator_params + " " + self.gameenginelist.getSelected().emulator_params
		else:
			emulator_params = self.gameenginelist.getSelected().emulator_params + self.romlist.getGame()
			emulator_params = self.gameenginelist.getSelected().rom_path + "/" + emulator_params

#		print self.gameenginelist.getSelected().executable + " " + emulator_params

		os.system(self.gameenginelist.getSelected().executable + " " + emulator_params)

class Authors():
	def __init__(self, screen):
		self.screen = screen
		self.authors = []
                self.font = pygame.font.Font('data/slkscr.ttf', 24)

		self.authors.append("Jost Stricker");
		self.authors.append("Troels Rasmussen");
		self.index = 0

	def update(self):
		time.sleep(4)
		self._draw(self.authors[self.index])
		self.index = self.index + 1

	def _draw(self, author):
		author_surface = self.font.render(author, 0, (128, 0, 0))
		self.screen.blit(author_surface, (1, 100))


class WhoDidThisView():
	def __init__(self, screen):
		self.screen = screen

		# Fill background
		self.background = pygame.Surface(screen.get_size())
		self.background = self.background.convert()
		self.background.fill((0, 0, 0))

		self.rotatinglogo = RotatingLogo()
		self.logo = pygame.sprite.RenderPlain((self.rotatinglogo))

		self.authors = Authors(screen)

	def refresh(self):
		self.screen.blit(self.background, (0, 0))

		# Rotate logo and move away
		if self.rotatinglogo.rotate or not self.rotatinglogo.clear:
			self.logo.update()
			self.logo.draw(self.screen)
		else:
			if self.rotatinglogo.clear:
				self.authors.update()

	def reset(self):
		self.rotatinglogo.reset()

class BackgroundMusic():
	def __init__(self):
		self.musicfile = os.path.join('data/sound', 'tune.ogg')
		self.backgroundmixer = pygame.mixer.music
	
	def play(self):
		self.backgroundmixer.load(self.musicfile)
		self.backgroundmixer.set_volume(0.2)
		self.backgroundmixer.play(-1)

class Sound():
	def __init__(self):
		self.soundmixer = pygame.mixer.Sound(os.path.join('data/sound', 'shift.ogg'))

	def play(self):
		self.soundmixer.play()

def main():
	
	# Initialize screen
	pygame.init()
	# pygame.FULLSCREEN
	pygame.display.set_caption('Arkaya')
	pygame.display.set_icon(arkaya_resources.load_icon())
	screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.NOFRAME)
	pygame.key.set_repeat(500, 150)

	gameenginelist = GameEngineList(screen)
	viewcontroller = ViewController(screen, gameenginelist)

	pygame.display.flip()

	# Play sound
	backgroundsound = BackgroundMusic()
	backgroundsound.play()
	
	# Initialise clock  
	clock = pygame.time.Clock()
	fullscreen = False
	
	# Event loop
	while 1:
		clock.tick(30)
	
		for event in pygame.event.get():
			if event.type == QUIT:
				pygame.quit()
				sys.exit(0)
			elif event.type == KEYDOWN:
				if event.key == K_ESCAPE:
					if isinstance(viewcontroller.getView(), EmulatorView):
						viewcontroller.setView("MainView")
					elif isinstance(viewcontroller.getView(), MainView):
						pygame.mixer.music.stop()
						viewcontroller.setView("WhoDidThisView")
					else:
						sys.exit(0)
				if event.key == K_LEFT:
					viewcontroller.left()
				if event.key == K_RIGHT:
					viewcontroller.right()
				if event.key == K_UP:
					viewcontroller.up()
				if event.key == K_DOWN:
					viewcontroller.down()
				if event.key == K_r:
					viewcontroller.reset()
				if event.key == K_RETURN or event.key == K_KP_ENTER:
					if isinstance(viewcontroller.getView(), MainView):
						print "Load EmulatorView"
						viewcontroller.setView("EmulatorView")
					elif isinstance(viewcontroller.getView(), EmulatorView):
						print "Starting emulator " + viewcontroller.getGameEngine().getName()
						pygame.mixer.music.pause()
						print viewcontroller.getView().runGame()
						
						pygame.mixer.music.unpause()
				if event.key == K_f:
					pygame.display.toggle_fullscreen()
					fullscreen = fullscreen == False
					pygame.mouse.set_visible(fullscreen == False)


		viewcontroller.refresh()
		pygame.display.flip()
		
if __name__ == '__main__': main()
